[inject templates/en.xd]
[gen-title Weak typing ≠ dynamic typing ≠ duck typing]
[p In the context of programming languages, many people seem to consider at least two of the terms [" weak typing], [" dynamic typing] and [" duck typing] to be synonymous. However, each of these has a completely different meaning and they can independently apply or not apply to a given language.]
[figure [link-image A swimming duck; images/duck.jpg]; Can a dynamic duck be strong?]
[section Weak/strong typing;
  [dfn A language is [term strongly typed] if it makes use of its type system to prevent logical errors, make APIs easier to understand, etc. A language is [term weakly typed] if it treats types only as an implementation detail and often allows implicit conversions. Note that this is really a continuous scale, not a binary distinction.]
  [example
    [p Strongly typed languages include Haskell, Rust, Nim, Julia, Python, Ruby, [...]]
    [p Weakly typed languages include C, JavaScript, PHP, Tcl, [...]]
  ]
  [p If you object to C being called a weakly typed language, consider the following example:]
  [code-block c; [raw<
    #include <fenv.h>
    #include <stdio.h>

    int main() {
      int a = 42;
      int b = &a;
      int c = FE_TOWARDZERO;
      int d = stdout;
      printf("%d\n", a * b + c / d);
      return 0;
    }
  ]]
  [p Here we have three variables representing completely different things [---] one is an integer, one is a pointer, one is a flag for the floating point environment and one is a file handle. However, C allows us to declare them all as [code c; int] and perform arithmetic on them.]
]
[section Dynamic/static typing;
  [dfn A language is [term statically typed] if the types of all values are known before running the program. A language is [term dynamically typed] if it's not statically typed.]
  [example
    [p Statically typed languages include C, Java, Haskell, Nim, Rust, [...]]
    [p Dynamically typed languages include Python, Common Lisp, Ruby, JavaScript, PHP, [...]]
  ]
  [p Note that a statically typed language doesn't necessarily require type declarations to be present on all variable declarations. Consider the following Nim program:]
  [code-block nim; [raw<
    import std/strutils

    stdout.write "What's your height in meters? "
    let height = stdin.readLine.parseFloat
    stdout.write "What's your weight in kilograms? "
    let weight = stdin.readLine.parseFloat
    let bmi = weight / (height * height)
    let diagnosis = "Your BMI is " & $bmi
    stdout.writeLine diagnosis
  ]]
  [p There are no type annotations in this program, yet all types are known and checked at compile time thanks to [term type inference].]
]
[section Duck typing;
  [dfn A language is [term duck typed] if procedures that work on generic types don't type-check until instantiation time.]
  [example Duck typed languages include Python, Ruby, Smalltalk, C++, Nim, [...]]
  [p The definition may sound a bit cryptic, so let's see a concrete example. Consider the following Haskell code:]
  [code-block haskell; [raw<
    middle :: a -> a -> a -> a
    middle x y z
      | x <= y && y <= z = y
      | z <= y && y <= x = y
      | y <= x && x <= z = x
      | z <= x && x <= y = x
      | otherwise = z
  ]]
  [p Trying to compile this produces the following error:]
  [<pre> [<samp> [raw<
    .code.tio.hs:3:5: error:
        • No instance for (Ord a) arising from a use of ‘<=’
          Possible fix:
            add (Ord a) to the context of
              the type signature for:
                middle :: forall a. a -> a -> a -> a
        • In the first argument of ‘(&&)’, namely ‘x <= y’
          In the expression: x <= y && y <= z
          In a stmt of a pattern guard for
                        an equation for ‘middle’:
            x <= y && y <= z
      |
    3 |   | x <= y && y <= z = y
      |     ^^^^^^
  ]]]
  [p This is because we've declared that [code haskell; middle] works for any type, but in fact it only works for types that support comparison. We can fix this by declaring that [code haskell; a] has to be an ordered type:]
  [code-block haskell; [raw middle :: Ord a => a -> a -> a -> a]]
  [p Now let's implement the same function in C++:]
  [code-block cpp; [raw<
    template <typename T> T middle(T x, T y, T z) {
    	if ((x <= y && y <= z) || (z <= y && y <= x)) {
    		return y;
    	}
    	if ((y <= x && x <= z) || (z <= x && x <= y)) {
    		return x;
    	}
    	return z;
    }
  ]]
  [p C++ doesn't complain. When we try to use the function on a non-ordered type, that's when we're going to get into trouble, but otherwise it's cool. This makes C++ a duck-typed language, even though it's statically typed.]
]
[comments]
